#===============================================================================
# radiovis-server
#===============================================================================
# Simple RadioVIS server for demonstration purposes.
# 
# Reads in text and image lines from text files and sends them out as per the
# RadioVIS specification to a nominated STOMP topic, as well as making them
# available on a Comet server.
# 
# The rotation time is hardcoded within this script, as well as a refresh period
# on the text lines - the script will check for any changes and update the text
# and/or slide lines accordingly.
#
# This script is meant to demonstrate the technology in its simplest form and
# is probably not good enough for a production system.
#===============================================================================
# 
# Copyright (C) 2010 Global Radio
# 
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# 
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#===============================================================================

import os, sys, getopt
import logging
import time
import stomp
from threading import Thread

# some configurable options here
host = 'localhost'
port = '61613'
username = None
password = None

class RadioVis:
    
    def __init__(self, connection, period=8):
        self.lines = []
        self.pos = 0
        self.period = period
        
        # try and set the default socket timeout
        import socket
        socket.setdefaulttimeout(5)
    
        log = logging.getLogger(self.__class__.__name__)
        
        # create watcher
        self.watcher = FileWatcher(self.read_lines)
                                
        # create the sender
        self.sender = Sender(connection, period, self)
                  
    def read_lines(self):
        file = open(self.path, 'r')
        self.lines = file.read().splitlines()
                  
    def start(self, topic, file): 
        self.path = file
        self.read_lines()
        self.sender.topic = topic
        self.watcher.path = file
        self.watcher.start()
        self.sender.start()
        
    def stop(self):
        self.sender.stop()
        self.watcher.stop()
    
class FileWatcher(Thread):
    
    def __init__(self, callback, period=10):
        self.log = logging.getLogger(self.__class__.__name__)
        Thread.__init__(self)
        Thread.setDaemon(self, True)
        Thread.setName(self, self.__class__.__name__)
        
        self.callback = callback
        self.period = period
        
        self.running = False
        
    def run(self):
        self.lastMod = os.stat(self.path).st_mtime
        
        # check file exists
        if not os.path.exists(self.path): raise ValueError('file %s does not exist' % self.path)

        self.running = True
        while self.running:
            self.log.debug('checking file last modified time')
            mtime = os.stat(self.path).st_mtime
            if self.lastMod != mtime:
                self.log.debug('file %s has been modified', self.path)
                self.callback()
                self.lastMod = mtime
            time.sleep(self.period)
            
    def stop(self):
        self.running = False
            
class Sender(Thread):
    
    def __init__(self, connection, period, vis):
        self.log = logging.getLogger(self.__class__.__name__)
        Thread.__init__(self)
        Thread.setName(self, self.__class__.__name__)
        
        self.connection = connection
        self.period = period
        self.vis = vis
        self.running = False
        
    def run(self):
        self.log.debug('starting sender')
        self.running = True
        while self.running:
            if self.vis.pos >= len(self.vis.lines): self.vis.pos = 0
            if len(self.vis.lines):
                self.log.debug('sending line: %s', self.vis.lines[self.vis.pos])
                self.connection.send(self.vis.lines[self.vis.pos], destination=self.topic)
                self.vis.pos += 1
            else:
                self.log.warning('no lines to send')
            time.sleep(self.period)
            
    def stop(self):
        self.running = False
    
from Tkinter import *
    
class App(Frame):
    
    def __init__(self, start_callback, stop_callback, topic='/topic/test', file=None, master=None):
        
        self.start_callback = start_callback
        self.stop_callback = stop_callback
        
        Frame.__init__(self, master)
        self.pack(expand=YES)
        
        button_row = Frame(self)
        button_row.pack(side=BOTTOM, expand=YES, fill=X)
        start_button = Button(button_row, text='Start', command=self.start)
        start_button.pack(side=LEFT, expand=YES, fill=X)
        self.start_button = start_button
        stop_button = Button(button_row, text='Stop', command=self.stop)
        stop_button.pack(side=RIGHT, expand=YES, fill=X)
        stop_button.configure(state=DISABLED)
        self.stop_button = stop_button
        
        status_row = Frame(self)
        status_row.pack(side=TOP, expand=YES, fill=X)
        Label(status_row, text='State').pack(side=LEFT)
        status = Label(status_row, bg='#FF0000', text='STOPPED')
        status.pack(side=RIGHT, expand=YES, fill=X)
        self.status = status
        
        file_row = Frame(self)
        file_row.pack(side=TOP, expand=YES, fill=X)
        Label(file_row, text='File').pack(side=LEFT, padx=5)
        self.file = StringVar()
        self.topic_entry = Entry(file_row, width=60, textvariable=self.file)
        self.topic_entry.pack(side=RIGHT, expand=YES, fill=X)
        self.file.set(file)
        
        topic_row = Frame(self)
        topic_row.pack(side=TOP, expand=YES, fill=X)
        Label(topic_row, text='Topic').pack(side=LEFT, padx=5)
        self.topic = StringVar()
        self.topic_entry = Entry(topic_row, width=60, textvariable=self.topic)
        self.topic_entry.pack(side=RIGHT, expand=YES, fill=X)
        self.topic.set(topic)
        
    def start(self):
        print 'starting...'
        self.start_callback(self.topic.get(), self.file.get())
        self.start_button.configure(state=DISABLED)
        self.stop_button.configure(state=NORMAL)
        self.status.configure(bg='#00FF00', text='STARTED')
        self.topic_entry.configure(state=DISABLED)
    
    def stop(self):
        print 'stopping...'
        self.stop_callback()
        self.start_button.configure(state=NORMAL)
        self.stop_button.configure(state=DISABLED)
        self.status.configure(bg='#FF0000', text='STOPPED')
        self.topic_entry.configure(state=NORMAL)
        
if __name__ == "__main__":  
    
    logging.basicConfig(stream=sys.stdout, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG)
    
    # connect to STOMP
    connection = stomp.Connection(host_and_ports = [(host, int(port))], user = username, passcode = password, reconnect_sleep_initial = 5, reconnect_sleep_increase = 0, reconnect_sleep_jitter = 0)
    Thread(target=connection.start).start()
    for i in range(5):
        if connection.is_connected(): break
        time.sleep(2)
    if not connection.is_connected():     
        log.critical('could not connect to notification server - EXITING')
        sys.exit(2)
    connection.connect()
    # start the connection
    import threading
    threading.Thread(target=connection.start).start()
    for i in range(5):
        if connection.is_connected(): break
        time.sleep(2)
    if not connection.is_connected():     
        log.critical('could not connect to notification server - EXITING')
        sys.exit(2)
    
    vis = RadioVis(connection, 8)
    
    # create the application
    myapp = App(vis.start, vis.stop, topic='/topic/test/text', file=os.path.abspath('textlines.txt'))
    myapp.master.title("Simple RadioVIS Sender")
    myapp.master.maxsize(1000, 400)
    
    # start the program
    myapp.mainloop() 
